﻿using Application.Common.Interfaces;
using Domain.Entities.Identity;
using FluentValidation;
using Microsoft.EntityFrameworkCore;

namespace Application.Features.Menus.Commands.Update;

/// <summary>
/// 校验菜单信息
/// </summary>
public class UpdateMenuCommandValidator : AbstractValidator<UpdateMenuCommand>
{
    private readonly IApplicationDbContext _context;
    public UpdateMenuCommandValidator(IApplicationDbContext context)
    {
        _context = context;

        RuleFor(x => x.Code)
            .MustAsync(BeUniqueCodeAsync).WithMessage("权限值重复！");

        RuleFor(x => x.ParentId).MustAsync(ValidParentIdAsync).WithMessage("非法移动！");
        RuleFor(x => x.MenuId).MustAsync(ValidIsNotSubordinateAsync).WithMessage("非法移动！");
    }

    /// <summary>
    /// 菜单移动是否合法
    /// </summary>
    /// <param name="command"></param>
    /// <param name="parentId"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    private async Task<bool> ValidParentIdAsync(UpdateMenuCommand command, long? parentId, CancellationToken cancellationToken)
    {
        if (parentId == null)
            return true;

        if (command.MenuId == parentId)
            return false;

        return await _context.Menus.AnyAsync(x => x.Id == parentId, cancellationToken);
    }

    /// <summary>
    /// 校验权限值是否唯一
    /// </summary>
    /// <param name="command"></param>
    /// <param name="code"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    private async Task<bool> BeUniqueCodeAsync(UpdateMenuCommand command, string? code, CancellationToken cancellationToken)
    {
        if (string.IsNullOrWhiteSpace(code))
        {
            return true;
        }
        var menu = await _context.Menus.FirstOrDefaultAsync(x => x.Code == code, cancellationToken);
        if (menu == null || menu.Id == command.MenuId)
        {
            return true;
        }
        return false;
    }



    /// <summary>
    /// 校验不是下级
    /// </summary>
    /// <param name="command"></param>
    /// <param name="Id"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    private async Task<bool> ValidIsNotSubordinateAsync(UpdateMenuCommand command, long Id, CancellationToken cancellationToken)
    {
        if (!command.ParentId.HasValue) return true;

        var menus = await _context.Menus.ToListAsync();
        if (!menus.Any()) return true;

        return !GetSubMenus(menus, Id).Any(x => x.Id == command.ParentId);


        static IEnumerable<Menu> GetSubMenus(List<Menu> menus, long Id)
        {
            var subMenus = menus.Where(d => d.ParentId == Id).ToList();
            foreach (var menu in subMenus.ToList()) // 使用 ToList() 创建一个副本以避免修改正在迭代的集合
            {
                subMenus.AddRange(GetSubMenus(menus, menu.Id));
            }
            return subMenus;
        }
    }
}